package ckw.gui;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
import java.util.logging.Level;

import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolTip;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;

import ckw.database.DatabaseManager;
import ckw.database.Election;
import ckw.database.OKW;
import ckw.database.OKW_Election;
import ckw.database.State;
import ckw.database.resultPattern.ElectionResultPattern;
import ckw.gui.wizards.WzdConfiguration;
import ckw.gui.wizards.WzdElection;
import ckw.network.ValidationThread;
import ckw.network.ConnectionC;
import ckw.network.Komisja;
import ckw.network.StanC;
import core.modules.Serializer;
import core.modules.LoggerModule;

/**
 * 
 * @author Maks Odpowiada za gui centrali
 * 
 */

public class MainWindowC {
	private static String title = "Daj glos - centrala";
	private static Shell shell;
	private static DatabaseManager db = null;
	public static StanC stanC = null;
	public static ConnectionC cm;
	public static Display display;

	private static Group dane = null;
	private static Table komisje;
	private static Tree wybory;
	private static Label lbl = null;
	private static Label lbl2 = null;
	private static LoggerModule logger;

	public MainWindowC(Display display) {
		
	    try {
	    	logger = new LoggerModule("logger.log", null);
	    } catch (IOException e) {
	    	e.printStackTrace();
			throw new RuntimeException("Problems with creating the log files");
	    }
	    logger.getLoggerInstance().log(Level.FINE, "Start centralnej komisji wyborczej");
		
		
		shell = new Shell(display, SWT.SHELL_TRIM & (~SWT.RESIZE) & (~SWT.MAX));
		shell.setText(title);
		db = DatabaseManager.getInstance();
		
		

		State state = db.getState();
		if (state != null) {
			stanC = (StanC) Serializer.SToO(state.getState());
			stanC.setNasluchiwanie(false);
			stanC.setTest(false);
			stanC.setWlaczony(false);
		} else
			stanC = new StanC();

		cm = new ConnectionC();
		cm.start(stanC, db);
		Thread checker = new Thread(new ValidationThread());
		checker.start();

		center(shell);

		logowanie();
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		cm.stop();
		checker.stop();

	    logger.getLoggerInstance().log(Level.FINE, "Zamkniecie centralnej komisji wyborczej");
		
	}

	// TODO: dodac jakies logowanie haslem?
	private static void logowanie() {
		dane = new Group(shell, SWT.SHADOW_ETCHED_IN);
		shell.setSize(300, 300);
		dane.setLocation(5, 0);
		dane.setSize(285, 265);

		logger.getLoggerInstance().log(Level.FINE, "Logowanie");
		// przycisk
		Button loguj = new Button(dane, SWT.PUSH);
		loguj.setSize(140, 25);
		loguj.setLocation(70, 80);
		loguj.setText("Start");

		loguj.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				dane.dispose();
				init();
			}
		});
	}

	private static void init() {
		TabFolder tabFolder = new TabFolder(shell, SWT.BORDER);
		konfiguracja(tabFolder);
		glosowanie(tabFolder);
		tabFolder.pack();
		shell.pack();
	}

	private static void startSerwera() {
		// TODO: pobieranie danych z bazy
		int port = 8888;
		if (!stanC.isWlaczony()) {
			try {
				cm.startServer(port, null);
				cm.listen();
			    logger.getLoggerInstance().log(Level.FINE, "Start serwera");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private static void konfiguracja(TabFolder tabFolder) {
		startSerwera();

		dane = new Group(tabFolder, SWT.SHADOW_ETCHED_IN);
		TabItem tabItem = new TabItem(tabFolder, SWT.SHADOW_ETCHED_IN);
		tabItem.setText("Konfiguracja");

		komisje = new Table(dane, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);
		komisje.setHeaderVisible(true);
		komisje.setLocation(10, 20);
		komisje.setSize(525, 435);

		TableColumn column1 = new TableColumn(komisje, SWT.NONE);
		column1.setText("Komisje");
		column1.setWidth(520);
		column1.setResizable(false);

		// przycisk serwera
		Button startServ = new Button(dane, SWT.PUSH);
		startServ.setSize(120, 20);
		startServ.setLocation(550, 20);
		startServ.setText("Restart serwera");

		Button testPolo = new Button(dane, SWT.PUSH);
		testPolo.setSize(120, 20);
		testPolo.setLocation(550, 60);
		testPolo.setText("Rozpocznij test");

		lbl = new Label(dane, SWT.LEFT);
		lbl.setSize(120, 50);
		lbl.setLocation(550, 100);
		changeState();

		Button generujConfig = new Button(dane, SWT.PUSH);
		generujConfig.setSize(120, 22);
		generujConfig.setLocation(550, 160);
		generujConfig.setText("Generuj config");

		Button wyslijDane = new Button(dane, SWT.PUSH);
		wyslijDane.setSize(120, 22);
		wyslijDane.setLocation(550, 200);
		wyslijDane.setText("Wyslij dane");

		// Button importBD = new Button(dane, SWT.PUSH);
		// importBD.setSize(120, 22);
		// importBD.setLocation(550, 240);
		// importBD.setText("Importuj baze");

		Button btnDatabase = new Button(dane, SWT.PUSH);
		btnDatabase.setSize(120, 22);
		btnDatabase.setLocation(550, 240);
		btnDatabase.setText("Zarzadzaj danymi");

		cm.aktualizacjaKomisji();
		aktualizujKomisje();

		komisje.addMouseTrackListener(new MouseTrackListener() {

			final ToolTip tip = new ToolTip(shell, SWT.BALLOON);

			@Override
			public void mouseHover(MouseEvent event) {
				Point pt = new Point(event.x, event.y);
				Table table = (Table) event.widget;
				System.out.println(table);
				TableItem item = table.getItem(pt);
				if (item != null) {
					tip.setVisible(false);
					Komisja k = cm.getKomisja((String) item.getData());
					if (k != null && k.getStan() != null
							&& k.getSocket() != null) {
						tip.setMessage("Info o komisji:"
								+ "\nWlaczony: "
								+ (k.getStan().isWlaczony() ? 1 : 0)
								+ "\nPolaczony: "
								+ (k.getStan().isPolaczenie() ? 1 : 0)
								+ "\nGlosRozp: "
								+ (k.getStan().isGlosowanieRozpoczete() ? 1 : 0)
								+ "\nKonczenieGlos: "
								+ (k.getStan().isKonczenieGlosowania() ? 1 : 0)
								+ "\nGlosZako: "
								+ (k.getStan().isGlosowanieZakonczone() ? 1 : 0)
								+ "\nKonfiguracja: "
								+ (k.getStan().isKonfiguracja() ? 1 : 0)
								+ "\nWybory: "
								+ (k.getStan().getElectionName() == null ? "brak"
										: k.getStan().getElectionName())
								+ "\nDaneWybor: "
								+ (k.getStan().isDaneWyborcze() ? 1 : 0));

					} else if (k != null) {
						tip.setMessage("Niepodlaczony, brak informacji");
					}
					Point loc = table.toDisplay(table.getLocation());
					tip.setLocation(loc.x + pt.x, loc.y + pt.y);
					tip.setVisible(true);

				} else {
					tip.setVisible(false);
				}

			}

			@Override
			public void mouseExit(MouseEvent event) {

			}

			@Override
			public void mouseEnter(MouseEvent event) {

			}
		});

		startServ.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				// tutaj nastepuje startowanie serwera i nasluchiwanie
				startSerwera();
			}
		});

		testPolo.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
			    logger.getLoggerInstance().log(Level.FINE, "Test polaczenia");
				TestWindow tw = new TestWindow(shell, cm, stanC);
			}
		});

		generujConfig.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				// Pobieramy z bazy wszystkie OKW
				ArrayList<OKW> okwList = (ArrayList<OKW>) db.getAll(OKW.class);

				WizardDialog wizardDialog = new WizardDialog(shell,
						new WzdConfiguration(okwList));
				wizardDialog.open();
			}
		});

		wyslijDane.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				if (stanC.isWlaczony()) {
					cm.wyslijDaneToAll();
				}
			}
		});

		// importBD.addListener(SWT.Selection, new Listener() {
		// public void handleEvent(Event event) {
		// FileDialog fileDialog = new FileDialog(shell, SWT.OPEN);
		//
		// String[] filterExtensions = new String[] { "*.xml", "*" };
		//
		// fileDialog.setFilterExtensions(filterExtensions);
		// fileDialog.open();
		// // TODO: zaimportowac baze z XML
		// }
		// });

		btnDatabase.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				// TODO: generowanie pliku XML z bazy
				DlgDb dlg = new DlgDb(shell);
				dlg.open();
				cm.aktualizacjaKomisji();
				aktualizujKomisje();
			}
		});

		dane.pack();
		tabItem.setControl(dane);

	}

	private static void glosowanie(TabFolder tabFolder) {

		dane = new Group(tabFolder, SWT.SHADOW_ETCHED_IN);
		TabItem tabItem = new TabItem(tabFolder, SWT.SHADOW_ETCHED_IN);
		tabItem.setText("Glosowanie");

		wybory = new Tree(dane, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);
		wybory.setHeaderVisible(true);
		wybory.setLocation(10, 20);
		wybory.setSize(525, 435);

		TreeColumn column = new TreeColumn(wybory, SWT.NONE);
		column.setText("Wybory");
		column.setWidth(520);
		column.setResizable(false);

		aktualizujWybory();

		Button tworzWybory = new Button(dane, SWT.PUSH);
		tworzWybory.setSize(120, 22);
		tworzWybory.setLocation(550, 20);
		tworzWybory.setText("Tworz wybory");

		Button printT = new Button(dane, SWT.PUSH);
		printT.setSize(120, 22);
		printT.setLocation(550, 60);
		printT.setText("Drukuj Tokeny");

		lbl2 = new Label(dane, SWT.LEFT);
		lbl2.setSize(120, 50);
		lbl2.setLocation(550, 100);
		changeState();

		Button showElectionResults = new Button(dane, SWT.PUSH);
		showElectionResults.setSize(120, 22);
		showElectionResults.setLocation(550, 200);
		showElectionResults.setText("Pokaz wyniki");

		showElectionResults.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				try {
					Election election = (Election) wybory.getSelection()[0]
							.getData();
					ElectionResultPattern electionResultPattern = DatabaseManager.getInstance().getElectionResult(election);
					if(electionResultPattern != null) {
						DlgElectionResults dlg = new DlgElectionResults(shell,
								electionResultPattern);
						dlg.open();
					} else {
						MessageBox mb = new MessageBox(shell);
						mb.setMessage("Wyniki niedostepne. Poczekaj na zakonczenie wyborow.");
						mb.open();
					}
					
				} catch (ArrayIndexOutOfBoundsException e2) {
				}
			}
		});
		/*
		 * startGlos = new Button(dane, SWT.PUSH); startGlos.setSize(120, 20);
		 * startGlos.setLocation(550, 20);
		 * startGlos.setText("Zacznij glosowanie");
		 * 
		 * zakGlos = new Button(dane, SWT.PUSH); zakGlos.setSize(120, 20);
		 * zakGlos.setLocation(550, 60); zakGlos.setText("Zakoncz glosowanie");
		 */

		/*
		 * startGlos.addListener(SWT.Selection, new Listener() { public void
		 * handleEvent(Event event) { if (stanC.isWlaczony()) { try {
		 * cm.startGlosowania(); } catch (Exception e) { e.printStackTrace(); }
		 * } } });
		 * 
		 * zakGlos.addListener(SWT.Selection, new Listener() { public void
		 * handleEvent(Event event) { if (stanC.isWlaczony()) { try {
		 * cm.endVote(); } catch (Exception e) { e.printStackTrace(); } } } });
		 */

		printT.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				if (wybory.getSelection().length > 0) {
					System.out.println(((Election) wybory.getSelection()[0]
							.getData()).getName());
					PrintTokens pt = new PrintTokens(shell, ((Election) wybory
							.getSelection()[0].getData()).getName());
				} else {
					MessageBox mb = new MessageBox(shell);
					mb.setMessage("Wybierz wybory");
					mb.open();
				}
			}
		});

		tworzWybory.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				WizardDialog wizardDialog = new WizardDialog(shell,
						new WzdElection());
				wizardDialog.open();
			}
		});

		dane.pack();
		tabItem.setControl(dane);

	}

	// aktualizuje liste
	public static void aktualizujKomisje() {
		logger.getLoggerInstance().log(Level.FINE, "Aktualizacja komisji");
		display.asyncExec(new Runnable() {
			public void run() {
				ArrayList<Komisja> kom = cm.getKomisje();
				komisje.clearAll();
				komisje.removeAll();

				for (Komisja k : kom) {
					TableItem item = new TableItem(komisje, SWT.NONE);
					item.setText(k.getName()
							+ " - "
							+ (k.getSocket() == null ? "niepolaczony"
									: "polaczony"));
					item.setData(k.getId());
				}
			}
		});
	}

	// aktualizuje wybory
	public static void aktualizujWybory() {
		logger.getLoggerInstance().log(Level.FINE, "Aktualizacja wyborow");
		display.asyncExec(new Runnable() {
			public void run() {
				wybory.removeAll();
				ArrayList<Election> elections = (ArrayList<Election>) db
						.getAll(Election.class);
				for (Election election : elections) {
					election = db.get(Election.class, election.getId());
					TreeItem trtmNewTreeitem = new TreeItem(wybory, SWT.NONE);
					trtmNewTreeitem.setText(election.getName() + " - "
							+ election.getStatusString());
					trtmNewTreeitem.setData(election);

					Set<OKW_Election> okw_elections = (Set<OKW_Election>) election
							.getOkw_elections();
					for (OKW_Election okw_election : okw_elections) {
						okw_election = db.get(OKW_Election.class,
								okw_election.getId());
						OKW okw = okw_election.getOkw();
						okw = db.get(OKW.class, okw.getId());
						TreeItem trtmNewTreeitem1 = new TreeItem(
								trtmNewTreeitem, SWT.NONE);
						trtmNewTreeitem1.setText(okw.getName()
								+ ", "
								+ okw.getIdentificationField()
								+ " - "
								+ (okw_election.getIsSend() ? "wyslane"
										: "nie wyslane") + ", "
								+ okw_election.getStatusString());
					}
				}
			}
		});
	}

	public static void rozpoczetoGlosowanie() {

	}

	public static void zakonczonoGlosowanie() {

	}

	public static void changeState() {
		logger.getLoggerInstance().log(Level.FINE, "Zmiana stanu");
		display.asyncExec(new Runnable() {
			public void run() {
				if (lbl != null)
					lbl.setText("Stan: " + "\nSerwer wlaczony: "
							+ (stanC.isWlaczony() ? 1 : 0));
				if (lbl2 != null)
					lbl2.setText(lbl.getText());
			}
		});

	}

	// wysrodkowuje okno
	public static void center(Shell shell) {
		Rectangle bds = shell.getDisplay().getBounds();
		Point p = shell.getSize();

		int nLeft = (bds.width - p.x) / 2;
		int nTop = (bds.height - p.y) / 2;

		shell.setBounds(nLeft, nTop, p.x, p.y);
	}

	public static void main(String[] args) {
		display = new Display();
		new MainWindowC(display);
		display.dispose();
	}

}
